package com.sunwayworld.baseline.business.labelprint.service.impl;

import com.deepoove.poi.config.ConfigureBuilder;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.sunwayworld.baseline.business.labelprint.dto.LabelPrintDTO;
import com.sunwayworld.baseline.business.labelprint.dto.LabelPrintDataDTO;
import com.sunwayworld.baseline.business.labelprint.service.LimsLabelPrintService;
import com.sunwayworld.basemodule.basedata.exporttemplate.bean.LimsExportTemplateBean;
import com.sunwayworld.basemodule.basedata.exporttemplate.service.LimsExportTemplateService;
import com.sunwayworld.basemodule.common.utils.ExportUtil;
import com.sunwayworld.basemodule.rm.equipment.bean.LimsEquipmentBean;
import com.sunwayworld.basemodule.rm.material.bean.LimsMaterialBean;
import com.sunwayworld.framework.context.ApplicationContextHelper;
import com.sunwayworld.framework.exception.FileException;
import com.sunwayworld.framework.exception.InvalidDataException;
import com.sunwayworld.framework.io.file.FileScope;
import com.sunwayworld.framework.mybatis.mapper.MatchPattern;
import com.sunwayworld.framework.mybatis.mapper.SearchFilter;
import com.sunwayworld.framework.restful.data.RestJsonWrapperBean;
import com.sunwayworld.framework.utils.EncryptUtils;
import com.sunwayworld.framework.utils.FileUtils;
import com.sunwayworld.framework.utils.StringUtils;
import com.sunwayworld.module.item.file.bean.CoreFileBean;
import com.sunwayworld.module.item.file.manager.CoreFileManager;
import com.sunwayworld.module.item.file.service.CoreFileService;
import com.sunwayworld.module.item.file.utils.CoreFileUtils;
import com.sunwayworld.module.sys.code.bean.CoreCodeBean;
import com.sunwayworld.module.sys.code.service.CoreCodeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName LimsLabelPrintServiceImpl
 * @Author zhoujq
 * @Date 2023/2/9
 * @Version 1.0
 **/
@Service
public class LimsLabelPrintServiceImpl implements LimsLabelPrintService {

    // 二维码颜色
    private static final int BLACK = 0xFF000000;
    // 二维码颜色
    private static final int WHITE = 0xFFFFFFFF;

    @Autowired
    @Lazy
    private LimsExportTemplateService limsExportTemplateService;

    @Autowired
    @Lazy
    private CoreFileManager coreFileManager;

    @Autowired
    @Lazy
    private CoreFileService coreFileService;

    @Autowired
    @Lazy
    private CoreCodeService coreCodeService;

    /**
     * 生成二维码
     *
     * @param text   二维码内容
     * @param width  二维码宽
     * @param height 二维码高
     */
    public static byte[] zxingCodeCreate(String text, int width, int height) {
        Map<EncodeHintType, String> his = new HashMap<EncodeHintType, String>();
        // 设置编码字符集
        his.put(EncodeHintType.CHARACTER_SET, "utf-8");
        try {
            // 1、生成二维码
            BitMatrix encode = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, his);

            // 2、获取二维码宽高
            int codeWidth = encode.getWidth();
            int codeHeight = encode.getHeight();

            // 3、将二维码放入缓冲流
            BufferedImage image = new BufferedImage(codeWidth, codeHeight, BufferedImage.TYPE_INT_RGB);
            for (int i = 0; i < codeWidth; i++) {
                for (int j = 0; j < codeHeight; j++) {
                    // 4、循环将二维码内容定入图片
                    image.setRGB(i, j, encode.get(i, j) ? BLACK : WHITE);
                }
            }
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ImageIO.write(image, "jpg", out);
            return out.toByteArray();
        } catch (WriterException e) {
            e.printStackTrace();
            System.out.println("二维码生成失败");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("生成二维码图片失败");
        }
        return null;
    }

    @Override
    public Long printEquipment(RestJsonWrapperBean wrapperBean) {
        Long fileId = null;
        List<LimsEquipmentBean> equipmentBeans = wrapperBean.parse(LimsEquipmentBean.class);
        List<CoreCodeBean> eqClass = coreCodeService.selectListByFilter(SearchFilter.instance().match("codeCategoryId", "eqClass").filter(MatchPattern.EQ));
        equipmentBeans.forEach(e -> {
            eqClass.stream().filter(ec -> ec.getCode().equals(e.getEquipClass())).findAny().ifPresent(ec -> {
                e.setExt$Item("equipClassName", ec.getCodeName());
            });
        });
        String templateCode = wrapperBean.getParamValue("templateCode");
        if (!equipmentBeans.isEmpty() && !StringUtils.isBlank(templateCode)) {
            // 查询标签模板
            List<LimsExportTemplateBean> limsExportTemplateBeans = limsExportTemplateService.selectListByFilter(SearchFilter.instance().match("templateCode", templateCode).filter(MatchPattern.EQ));

            if (!limsExportTemplateBeans.isEmpty()) {
                CoreFileBean reportTemplate = coreFileService.selectById(limsExportTemplateBeans.get(0).getTemplateFileId());
                String reportTemplatePath = CoreFileUtils.getLocalPath(reportTemplate).toString();
                if (StringUtils.isBlank(reportTemplatePath) || !(new File(reportTemplatePath).exists())) {
                    throw new InvalidDataException("LIMS.BUSINESS.REPORT.ALERT.NO_TEMPLATE");
                }
                // 填充模板，生成文件
                try (InputStream templateFile = new FileInputStream(reportTemplatePath); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
                    ExportUtil.build(templateFile, builder -> this.buildEquipmentTagParams(builder, equipmentBeans), os);

                    // 生成的文件导入到系统
                    fileId = ApplicationContextHelper.getNextIdentity();
                    CoreFileBean insertCoreFile = new CoreFileBean();
                    insertCoreFile.setId(fileId);
                    insertCoreFile.setTargetId("T_LIMS_SAMPLE_BARCODE" + "$" + StringUtils.randomUUID());//分类报告
                    insertCoreFile.setName("设备标签.docx");
                    insertCoreFile.setFileExt(FileUtils.getFileExtension(insertCoreFile.getName()));
                    insertCoreFile.setMd5Name(EncryptUtils.MD5Encrypt(fileId + "$" + insertCoreFile.getName()));
                    insertCoreFile.setScope(FileScope.secure.name());
                    insertCoreFile.setSize((long) os.size());
                    insertCoreFile.setTimes(0L);
                    insertCoreFile.setExt("docx");
                    insertCoreFile.setDownloadable("1");
                    insertCoreFile.setCreatedTime(LocalDateTime.now());
                    coreFileService.getDao().insert(insertCoreFile);

                    try (ByteArrayInputStream in = new ByteArrayInputStream(os.toByteArray())) {
                        coreFileManager.upload(insertCoreFile, in);
                    }
                } catch (IOException e) {
                    throw new FileException(e);
                }
            }
        }
        return fileId;
    }

    private LabelPrintDataDTO buildEquipmentTagParams(ConfigureBuilder configureBuilder, List<LimsEquipmentBean> equipmentBeans) {
        LabelPrintDataDTO printDataDTO = new LabelPrintDataDTO();
        String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        List<LabelPrintDTO> printDTOS = new ArrayList<>();
        equipmentBeans.forEach(e -> {
            LabelPrintDTO dto = new LabelPrintDTO();
            dto.setDate(date);
            dto.setEquipCode(e.getEquipCode());
            dto.setEquipName(e.getEquipName());
            dto.setManufacturer(e.getManufacturer());
            dto.setSpecificationModel(e.getSpecificationModel());
            if (!StringUtils.isEmpty(e.getExt$Item("equipClassName"))) {
                dto.setEqClass(e.getExt$Item("equipClassName"));
            }
            if (!StringUtils.isBlank(e.getEquipCode())) {
                dto.setBarcode(zxingCodeCreate(e.getEquipCode(), 400, 400));
            }
            dto.setBarCodeSize(50);
            printDTOS.add(dto);
        });
        printDataDTO.setDataList(printDTOS);
        return printDataDTO;
    }

    @Override
    public Long printMaterial(RestJsonWrapperBean wrapperBean) {
        Long fileId = null;
        List<LimsMaterialBean> materialBeans = wrapperBean.parse(LimsMaterialBean.class);
        String templateCode = wrapperBean.getParamValue("templateCode");
        if (!materialBeans.isEmpty() && !StringUtils.isBlank(templateCode)) {
            // 查询标签模板
            List<LimsExportTemplateBean> limsExportTemplateBeans = limsExportTemplateService.selectListByFilter(SearchFilter.instance().match("templateCode", templateCode).filter(MatchPattern.EQ));

            if (!limsExportTemplateBeans.isEmpty()) {
                CoreFileBean reportTemplate = coreFileService.selectById(limsExportTemplateBeans.get(0).getTemplateFileId());
                String reportTemplatePath = CoreFileUtils.getLocalPath(reportTemplate).toString();
                if (StringUtils.isBlank(reportTemplatePath) || !(new File(reportTemplatePath).exists())) {
                    throw new InvalidDataException("LIMS.BUSINESS.REPORT.ALERT.NO_TEMPLATE");
                }
                // 填充模板，生成文件
                try (InputStream templateFile = new FileInputStream(reportTemplatePath); ByteArrayOutputStream os = new ByteArrayOutputStream()) {
                    ExportUtil.build(templateFile, builder -> this.buildMaterialTagParams(builder, materialBeans), os);

                    // 生成的文件导入到系统
                    fileId = ApplicationContextHelper.getNextIdentity();
                    CoreFileBean insertCoreFile = new CoreFileBean();
                    insertCoreFile.setId(fileId);
                    insertCoreFile.setTargetId("T_LIMS_SAMPLE_BARCODE" + "$" + StringUtils.randomUUID());//分类报告
                    insertCoreFile.setName("材料标签.docx");
                    insertCoreFile.setFileExt(FileUtils.getFileExtension(insertCoreFile.getName()));
                    insertCoreFile.setMd5Name(EncryptUtils.MD5Encrypt(fileId + "$" + insertCoreFile.getName()));
                    insertCoreFile.setScope(FileScope.secure.name());
                    insertCoreFile.setSize((long) os.size());
                    insertCoreFile.setTimes(0L);
                    insertCoreFile.setExt("docx");
                    insertCoreFile.setDownloadable("1");
                    insertCoreFile.setCreatedTime(LocalDateTime.now());
                    coreFileService.getDao().insert(insertCoreFile);

                    try (ByteArrayInputStream in = new ByteArrayInputStream(os.toByteArray())) {
                        coreFileManager.upload(insertCoreFile, in);
                    }
                } catch (IOException e) {
                    throw new FileException(e);
                }
            }
        }
        return fileId;
    }

    private LabelPrintDataDTO buildMaterialTagParams(ConfigureBuilder configureBuilder, List<LimsMaterialBean> materialBeans) {
        LabelPrintDataDTO printDataDTO = new LabelPrintDataDTO();
        String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        List<LabelPrintDTO> printDTOS = new ArrayList<>();
        materialBeans.forEach(m -> {
            LabelPrintDTO dto = new LabelPrintDTO();
            dto.setDate(date);
            dto.setMatCode(m.getMatCode());
            dto.setMatName(m.getMatName());
            dto.setSpecifications(m.getSpecifications());
            dto.setCargoNo(m.getCargoNo());
            dto.setBatchNo("-");
            dto.setExpiredTime("-");
            dto.setStorageConditions("-");

            printDTOS.add(dto);
        });
        printDataDTO.setDataList(printDTOS);
        return printDataDTO;
    }
}
